package cn.jasonone.jfx.manager;

import cn.hutool.core.util.ReflectUtil;
import cn.jasonone.jfx.config.properties.JfxProperties;
import cn.jasonone.jfx.context.BaseController;
import cn.jasonone.jfx.factory.SceneFactory;
import cn.jasonone.jfx.factory.StageFactory;
import cn.jasonone.jfx.mananger.FxmlManager;
import cn.jasonone.jfx.mananger.SceneManager;
import cn.jasonone.jfx.mananger.StageManager;
import cn.jasonone.jfx.util.NodeUtil;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import lombok.Setter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;

/**
 * 场景管理器实现类
 *
 * @author xujie
 * @version 1.0
 * @date 2021/12/22 10:44
 */
@Component("sceneManager")
public class JfxSceneManager implements SceneManager {
    private static final String PRIMARY_SCENE_KEY = "PRIMARY";
    @Resource
    private SceneFactory sceneFactory;
    @Resource
    private JfxProperties jfxProperties;
    @Resource
    private FxmlManager fxmlManager;
    private StageManager stageManager;
    @Resource
    private NodeUtil nodeUtil;

    @Override
    public Scene getPrimaryScene() {
        return sceneFactory.getScene(PRIMARY_SCENE_KEY, jfxProperties.getWidth(), jfxProperties.getHeight());
    }

    @Override
    public Scene createScene(Class controllerType) throws Exception {
        Scene scene = sceneFactory.getScene(controllerType);
        bindRootParent(scene, controllerType);
        return scene;
    }

    @Override
    public void bindRootParent(Scene scene, Parent root) {
        update(scene.getRoot(), null, scene);
        scene.setRoot(root);
        update(root, scene, null);
    }

    @Override
    public void bindRootParent(Scene scene, Class controllerType) {
        try {
            Parent pane = fxmlManager.loadPane(controllerType);
            bindRootParent(scene, pane);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void update(Parent root, Scene scene, Scene oldScene) {
        // 更新场景中所有节点的舞台数据
        Set<BaseController> controllers = nodeUtil.getControllers(root, c -> c instanceof BaseController);
        for (BaseController controller : controllers) {
            ReflectUtil.setFieldValue(controller, "scene", scene);
            if (scene == null) {
                controller.removeScene(oldScene);
            } else {
                controller.addScene(scene);
            }
        }
    }

    @Override
    public <P extends Parent> P getRootParent(Scene scene) {
        return (P) scene.getRoot();
    }

    @Override
    public void setStageManager(StageManager stageManager) {
        this.stageManager = stageManager;
        fxmlManager.setStageManager(stageManager);
        fxmlManager.setSceneManager(this);
    }
}
